package com.bjpowernode.ba03;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Aspect：是aspect框架的注解. 作用：表示当前类是切面类
 * 切面类：是用来给业务方法增加功能的类,在这个类有切面功能的代码
 * 位置：在类定义的上面
 */
@Aspect
public class MyAspect {
    /**
     * 后置通知定义方法,方法是实现切面功能的.
     * 方法的定义要求:
     * 1.公共方法public.
     * 2.必须有返回值,推荐使用Object.
     * 3.方法名称自定义.
     * 4.方法有参数,固定参数ProceedingJoinPint
     */

    /***
     * @Around:环绕通知
     * 属性:value切入点表达式
     * 位置:在方法的定义上面
     * 特点:
     * 1.它的功能是最强的.
     * 2.在目标方法的前后都能增强功能
     * 3.控制目标方法是否被调用执行
     * 4.修改原理的目标方法执行结果,影响最后的调用结果
     * 环绕通知:等同于jdk动态代理(类似实现InvocationHandle)
     * 参数:固定参数ProceedingJoinPint就等于Method
     *      作用:执行目标方法的
     * 返回值:就是目标方法的执行结果是可以修改的.
     *
     * 环绕通知经常做事务,在目标方法执行前开启事务,然后执行目标方法,在执行完目标方法后提交事务
     * @return
     */
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 获取方法的参数用来控制方法执行
        Object arg = null;
        Object[] args = proceedingJoinPoint.getArgs();
        String name = null;
        if (args!= null && args.length > 1){
            arg = args[0];
            name = (String)arg;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 实现环绕通知
        Object result = null;
        System.out.println("环绕通知:在目标方法执行前,输出时间->" + format.format(new Date()));
        // 1.调用目标方法
       if ("张三".equals(name)) {
           result = proceedingJoinPoint.proceed(); // method.invoke(); Object result = doFirst();
       }
        // 2.在目标方法前后加入功能或者事务
        System.out.println("环绕通知:在目标方法执行后,提交事务.");
       // 修改返回值
        if (result != null) {
            result  = name;
        }
        return result;
    }

}
